package com.kajespero.model.annotation.process;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import com.kajespero.model.IdentifierVOBean;
import com.kajespero.model.annotation.MappedValue;
import com.kajespero.utils.PersistManagerJdoHelper;
import com.kajespero.vo.IdentifierVO;

public class MappedValueProcess {

	public static <T extends IdentifierVO<?>> T processPostLoad(T instance) {
		List<Field> fields = findAttributes(instance);
		for (Field field : fields) {
			// get to persist value for set not persist bean
			// transform key to VO
			MappedValue annotation = field.getAnnotation(MappedValue.class);
			Field persistAttribute = findAttribute(instance,annotation.mappedBy());
			Class<?> searchClass = annotation.type();
			try {
				persistAttribute.setAccessible(true);
				Object key = persistAttribute.get(instance);
				persistAttribute.setAccessible(false);
				if(key != null){
					Object value = PersistManagerJdoHelper.getPersistenceManager().getObjectById(searchClass, key);
					field.setAccessible(true);
					field.set(instance, value);
					field.setAccessible(false);
				}
				else {
					processPreSave(instance);
				}
			} catch (IllegalArgumentException e) {
				field.setAccessible(false);
			} catch (IllegalAccessException e) {
				field.setAccessible(false);
			}

		}
		return instance;
	}
	
	public static <T extends IdentifierVO<?>> Collection<T> processPostLoad(Collection<T> list){
		Collection<T> returnList = new ArrayList<T>();
		for(T instance : list){
			returnList.add(MappedValueProcess.processPostLoad(instance));
		}
		return returnList;
	}

	public static <T extends IdentifierVO<?>> T processPreSave(T instance) {
		List<Field> fields = findAttributes(instance);
		for (Field field : fields) {
			// set to persist value for get not persist bean key
			// transform VO to Key
			MappedValue annotation = field.getAnnotation(MappedValue.class);
			Field persistAttribute = findAttribute(instance,annotation.mappedBy());
			try {
				field.setAccessible(true);
				IdentifierVO<?> value = (IdentifierVO<?>) field.get(instance);
				field.setAccessible(false);
				if(value != null){
					Object key = ((IdentifierVOBean<?>)value).getKey();
					persistAttribute.setAccessible(true);
					persistAttribute.set(instance, key);
					persistAttribute.setAccessible(false);
				}
				
			} catch (IllegalArgumentException e) {
				persistAttribute.setAccessible(false);
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				persistAttribute.setAccessible(false);
				e.printStackTrace();
			}
		}
		return instance;
	}

	private static <T> List<Field> findAttributes(T instance) {
		List<Field> fields = new ArrayList<Field>();
		Field[] attributes = instance.getClass().getDeclaredFields();
		for (Field attribute : attributes) {
			Annotation annotation = attribute.getAnnotation(MappedValue.class);
			if (annotation != null ) {
				fields.add(attribute);
			}
		}
		return fields;
	}

	private static <T> Field findAttribute(T instance, String name) {
		Field[] attributes = instance.getClass().getDeclaredFields();
		for (Field attribute : attributes) {
			if (attribute.getName().equals(name)) {
				return attribute;
			}
		}
		return null;
	}

}
